



#需要连外网

import glumpy
from glumpy import app, gloo, gl, glm, data
from glumpy.graphics.collections import PointCollection
import numpy as np 

import cv2


print(123)
print(123)
print(123)
print(123)
print(123)








vertex = """
    attribute vec2 position;
    attribute vec2 texcoord;
    varying vec2 v_texcoord;
    void main()
    {
        gl_Position = vec4(position, 0.0, 1.0);
        v_texcoord = texcoord;
    }
"""

fragment = """
    uniform sampler2D texture;
    uniform vec3 base_color;
    varying vec2 v_texcoord;
    void main()
    {
        gl_FragColor = vec4(base_color,0)+texture2D(texture, v_texcoord);
    }
"""

window = app.Window(width=1024, height=1024, aspect=1)


def screen_to_device(p):
    ws = window.get_size()
    p[0] /= ws[0]/2
    p[1] /= ws[1]/2
    p -= 1
    p[1] *= -1
    return p
    
class ImageWarper:
    def __init__(self, m, n):
        self.m, self.n = m, n
        
        # bezier control points
        self.ctrl_points = PointCollection("agg", color="local", size="local")
        x, y = np.meshgrid(np.linspace(-0.9, 0.9, m), np.linspace(-0.9, 0.9, m))
        p = np.column_stack([x.reshape(-1), y.reshape(-1), -np.zeros(m*m)])
        color = np.tile(np.r_[1, 1, 1, 1], m*m).reshape((-1, 4))
        self.ctrl_points.append(p, color=color, size=20*np.ones(len(color)))
        window.attach(self.ctrl_points["transform"])
        window.attach(self.ctrl_points["viewport"])

        # bezier mesh with uv supported
        self.bezier_mesh = gloo.Program(vertex, fragment, count=n*n)
        

    def pick(self, p):
        # function to pick bezier control points
        p = screen_to_device(p)
        dis = np.linalg.norm(self.ctrl_points['position'][:, :2]-p, axis=1)
        min_ind = np.argmin(dis)
        self.pick_ind = None
        if dis[min_ind]*np.linalg.norm(window.get_size()) < 30:
            self.pick_ind = min_ind
    
    def bezier_point(self, u, v):
        # de Casteljau's Algorithm
        # https://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/surface/bezier-de-casteljau.html
        P_n = np.copy( self.ctrl_points['position'].reshape((self.m, self.m, 3)))
        for k in range(self.m):
            for i in range(self.m-k-1):
                for j in range(self.m-k-1):
                    p_v0 = P_n[i, j]*(1-v) + P_n[i, j+1]*v  
                    p_v1 = P_n[i+1, j]*(1-v) + P_n[i+1, j+1]*v  
                    P_n[i,j] = p_v0*(1-u) + p_v1*u
        return P_n[0, 0]
        
    def update_bezier_mesh(self): 
        # subdivision mesh of the bezier control proxy
        n = self.n 
        P_n = np.zeros((n, n, 3))
        UV = np.zeros((n, n, 2))
        for u_i, u in enumerate(np.linspace(0, 1, n)):
            for v_i, v in enumerate(np.linspace(0, 1, n)):
                P_n[u_i, v_i] = self.bezier_point(u, v)
                UV[u_i, v_i] = (v, 1-u)
        self.bezier_mesh['position'] = P_n[:,:,:2].reshape((-1, 2))
        self.bezier_mesh['texcoord'] = UV.reshape((-1, 2))

        F = []
        for i in range(n-1):
            for j in range(n-1):
                F.append(np.r_[i*n+j+1, i*n+j, (i+1)*n+j+1])
                F.append(np.r_[i*n+j, (i+1)*n+j, (i+1)*n+j+1])
        self.image_faces = np.array(F, dtype=np.uint32).reshape(-1)
        self.image_faces = self.image_faces.view(gloo.IndexBuffer)
        
            
image_warper = ImageWarper(4, 10)    
#val1 = data.get(str("people.png"))
image_warper.bezier_mesh['texture'] = data.get("lena.png")
image_warper.update_bezier_mesh()

@window.event
def on_draw(dt):
    window.clear()
    #draw warped image
    image_warper.bezier_mesh['base_color'] = np.r_[0, 0, 0]
    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
    image_warper.bezier_mesh.draw(gl.GL_TRIANGLES, image_warper.image_faces)
    image_warper.bezier_mesh['base_color'] = np.r_[1, 1, 1]
    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
    image_warper.bezier_mesh.draw(gl.GL_TRIANGLES, image_warper.image_faces)
    image_warper.ctrl_points.draw()
    
@window.event
def on_mouse_press(x, y, button):
    image_warper.pick(np.array([x, y], dtype=np.float))

@window.event
def on_mouse_drag(x, y, dx, dy, button):
    if image_warper.pick_ind is None: return
    # bezier control point draging
    p = screen_to_device(np.r_[x, y])
    image_warper.ctrl_points['position'][image_warper.pick_ind, :2] = p
    image_warper.update_bezier_mesh()

app.run()